package hr.ctg.domain.action.objekt;

import hr.ctg.domain.model.Objekt;
import hr.ctg.domain.model.Osobina;
import hr.ctg.domain.model.Smjestaj;
import hr.ctg.service.dao.ObjektDAO;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.faces.context.FacesContext;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.log.Log;

/**
 * 
 * @author igor
 */

@Scope(ScopeType.EVENT)
@Name(value = "objektCompare")
public class ObjektCompareAction {
	@Logger
	Log log;

	@In
	private ObjektDAO objektDAO;

	@In
	private Map<String, String> messages;

	@RequestParameter
	Integer idObjekta;

	List<Integer> idListForCompare = new ArrayList<Integer>();

	public String selectObjekt(final Objekt objekt) {
		log.debug("Ulazim u select OBJEKT method!!");
		// if (idListForCompareStr != null) {
		// idListForCompare.addAll((List) new ListIConverter().getAsObject(
		// null, null, idListForCompareStr));
		// }
		if (idListForCompare.contains(objekt.getIdObjekta())) {
			idListForCompare.remove(idListForCompare.indexOf(objekt
					.getIdObjekta()));
		} else {
			idListForCompare.add(objekt.getIdObjekta());
		}
		return null;
	}

	@Factory(value = "objektiForCompare", scope = ScopeType.EVENT)
	public List<Objekt> buildObjektiForCompare() {
		final List<Objekt> coMap = new ArrayList<Objekt>();
		for (final Integer idObjekta : idListForCompare) {
			coMap.add(objektDAO.find(idObjekta));
		}
		idListForCompare.clear();
		return coMap;
	}

	@SuppressWarnings("unchecked")
	@Factory("comparisonTable")
	public Map<String, List<String>> buildCompareTable() {
		log.debug("Gradim tablicu za usporedbu...");
		final Map<String, List<String>> comparisonTable = new HashMap<String, List<String>>();

		int oCounter = 0;
		for (final Integer idObjekta : idListForCompare) {
			// Za sve prisutne osobine dodaj NISTA znak
			log.debug("Crrnt: " + comparisonTable);
			final Iterator i = comparisonTable.entrySet().iterator();
			while (i.hasNext()) {
				final Map.Entry<Integer, List> entry = (Map.Entry) i.next();
				final List l = entry.getValue();
				l.add("-");
			}
			log.debug("after: " + comparisonTable);
			final Objekt o = objektDAO.find(idObjekta);
			log.debug(">>> Objekt: " + o.getNaziv());
			for (final Osobina oo : o.getOsobinas()) {
				log.debug(">>>>>> Osobina: " + oo.getIdOsobine() + ""
						+ oo.getNaziv());

				final String mbKey = "label.osobina." + oo.getIdOsobine();
				// dohvati postojecu listu vrijednosti za ovu osobinu iz tablice
				List l = comparisonTable.get(messages.get(mbKey));

				if (null != l) {
					// AKO lista postoji ukloni zadnji NISTA znak i na njen kraj
					// dodaj vrijednost ove osobine ovog objekta
					l.remove(l.size() - 1);
					l.add("+");
				} else {
					// AKO Lista ne postoji, stvori je i napuni s NISTA znakom
					// za sve prethodne objekte
					l = new ArrayList();
					for (int idx = 0; idx < oCounter; idx++) {
						l.add("-");
					}
					// Na njen kraj dodaj vrijednost ove osobine ovog objekta
					l.add("+");
					// dodaj je u tablicu
					comparisonTable.put(messages.get(mbKey), l);
				}
			}
			processSmjestaj(o, comparisonTable, oCounter);
			oCounter++;
		}

		log.debug("Locale koristen u app je: "
				+ FacesContext.getCurrentInstance().getViewRoot().getLocale());
		log.debug("Locale u bundleu mess je: "
				+ FacesContext.getCurrentInstance().getApplication()
						.getMessageBundle());
		final ResourceBundle rb = FacesContext.getCurrentInstance()
				.getApplication().getResourceBundle(
						FacesContext.getCurrentInstance(),
						"org.jboss.seam.jsf.SeamApplicationMessageBundle");
		log.debug("Bundle adres            : " + rb);

		return comparisonTable;
	}

	/**
	 * Za objekt koji ima definiran smjestaj puni comparison table.
	 * 
	 * @param o
	 * @param comparisonTable
	 * @param oCount
	 */
	private final void processSmjestaj(final Objekt o,
			final Map<String, List<String>> comparisonTable, final int oCounter) {
		final Smjestaj s = o.getSmjestaj();
		if (null == s)
			return;
		final Method[] methods = Smjestaj.class.getMethods();
		for (final Method method : methods) {
			final String methodTarget = getGetterTarget(method);
			if (null == methodTarget)
				continue;
			if ("objekt".equals(methodTarget))
				continue;
			if ("class".equals(methodTarget))
				continue;
			if ("checkinminute".equals(methodTarget))
				continue;
			if ("checkinsat".equals(methodTarget))
				continue;
			if ("idobjekta".equals(methodTarget))
				continue;
			if ("checkoutminute".equals(methodTarget))
				continue;
			if ("checkoutsat".equals(methodTarget))
				continue;

			try {
				final Object targetValue = method.invoke(s);
				if (null == targetValue)
					continue;
				final String key = messages.get("label.smjestaj."
						+ methodTarget);
				processList(comparisonTable, oCounter, targetValue, key);
			} catch (final InvocationTargetException e) {
				log.error(e.getMessage(), e);
			} catch (final Exception e) {
				log.error(e.getMessage(), e);
			}
		}
	}

	private final void processList(
			final Map<String, List<String>> comparisonTable,
			final int oCounter, final Object value, final String key) {
		// dohvati postojecu listu vrijednosti za ovu osobinu iz tablice
		List<String> l = comparisonTable.get(key);
		if (null != l) {
			// AKO lista postoji ukloni zadnji NISTA znak i na njen kraj
			// dodaj vrijednost ove osobine ovog objekta
			l.remove(l.size() - 1);
			l.add(value.toString());
		} else {
			// AKO Lista ne postoji, stvori je i napuni s NISTA znakom
			// za sve prethodne objekte
			l = new ArrayList<String>();
			for (int idx = 0; idx < oCounter; idx++) {
				l.add("-");
			}
			// Na njen kraj dodaj vrijednost ove osobine ovog objekta
			l.add(value.toString());
			// dodaj je u tablicu
			comparisonTable.put(key, l);
		}
	}

	public boolean isForCompare(final Integer idObjekta) {
		if (idListForCompare == null)
			return false;
		return idListForCompare.contains(idObjekta);
	}

	public List<Integer> getIdListForCompare() {
		return idListForCompare;
	}

	public void setIdListForCompare(List<Integer> list) {
		this.idListForCompare = list;
	}

	// izbaci ovo u neku util klasu
	public static String getGetterTarget(final Method method) {
		if (!method.getName().startsWith("get"))
			return null;
		if (method.getParameterTypes().length != 0)
			return null;
		if (void.class.equals(method.getReturnType()))
			return null;
		return method.getName().substring(3).toLowerCase();
	}
}
